package io.renren.common.utils.excel;

import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * Created with IntelliJ IDEA.
 * User: 齐丹枫
 * Date: 2018/5/25
 * Time: 14:49
 * To change this template use File | Settings | File Templates.
 * Description:
 */
@Component
public class ExcelUtils {


    private ExcelDataCreater excelDataCreater;

    private static SXSSFWorkbook wb;

    private  class GenerateSheetRiceTask implements Callable<Integer> {
        private String[] lableNames;
        private String[] columnNames;
        private int form;
        private int to;
        private  Map<String,Object> params;

        private int sheetNum=1;

        public GenerateSheetRiceTask(String[] lableNames, String[] columnNames,
                                     Map<String,Object> params,int sheetNum,int form,int to) {
            this.lableNames = lableNames;
            this.columnNames = columnNames;
            this.sheetNum = sheetNum;
            this.form = form;
            this.to = to;
            this.params = params;
        }

        @Override
        public Integer call() throws Exception {

            Map<String,Object> map=new HashMap();
            map.putAll(params);
            map.put("offset",form);
            map.put("limit",to);

            int size = getDate("sheet" + sheetNum, lableNames, columnNames, map, excelDataCreater);
            return size ;
        }
    }


    public void export(HttpServletResponse response, String fileName, String[] lableNames,
                       String[] columnNames, Map<String,Object> params, ExcelDataCreater dataCreater) throws Exception {

        response.setContentType("application/force-download"); // 设置下载类型
        response.setHeader("Content-Disposition","attachment;filename="
                .concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8")))); // 设置文件的名称
        OutputStream os = response.getOutputStream(); // 输出流

        wb = new SXSSFWorkbook(1000);   //内存中保留 1000 条数据，以免内存溢出，其余写入 硬盘
        excelDataCreater = dataCreater;

        int total = excelDataCreater.queryTotalForExcel(params);
        System.out.println("查询总数据："+total);
        ExecutorService pool = excelDataCreater.getPool(total);

        int threads = excelDataCreater.getThreads();

        int part = total / threads;

        ArrayList<Future<Integer>> futures = new ArrayList<>();
        for (int i = 0; i < threads; i++) {
            futures.add(pool.submit(new GenerateSheetRiceTask(lableNames, columnNames, params, i, i * part, part)));
        }

        Integer a=0;
        for (Future future:futures
                ) {

            a += (Integer) (future.get());
        }
        System.out.println("导出的总数据："+a);

        wb.write(os);
    }


    private  int getDate(String sheetName, String[] lableNames, String[] columnNames, Map<String,Object> params,
                        ExcelDataCreater excelDataCreater){

        long l = System.currentTimeMillis();
        List<Object> list = excelDataCreater.queryDataForExcel(params);

        System.out.println("线程"+Thread.currentThread().getName()+"执行的时间："+(System.currentTimeMillis()-l)/1000);

        List<Map<String, Object>> maps = list.parallelStream()
                .map(o -> beanToMap(o)).collect(Collectors.toList());

        try {
            generateExcel(wb,lableNames,columnNames,maps,sheetName);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return list.size();

    }

    /**
     * JavaBean转Map
     * @param obj
     * @return
     */
    public static Map<String, Object> beanToMap(Object obj) {

        Map<String, Object> params = new HashMap<String, Object>(0);
        try {
            PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(obj);
            for (int i = 0; i < descriptors.length; i++) {
                String name = descriptors[i].getName();
                if (!StringUtils.equals(name, "class")) {
                    params.put(name, propertyUtilsBean.getNestedProperty(obj, name));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return params;
    }


    public  void generateExcel( SXSSFWorkbook wb,
                              String[] lableNames,String[] columnNames,List<Map<String,Object>> list,String sheetName) throws IOException {
        //获得该工作区的第一个sheet
        ZipSecureFile.setMinInflateRatio(-1.0d);
        System.out.println(sheetName);
        Sheet sheet  = wb.createSheet(sheetName);

        generateCellMergedRegion(wb,sheet,0,0,0,lableNames.length-1, LocalDateTime.now().toString());

        generateTitle(wb,sheet,lableNames);

        generateContentRowAsyn(wb,sheet,columnNames,list);


    }


    private static CellStyle setHeadStyle(Workbook workbook, Sheet sheet){
        //标题头样式
        CellStyle cellStyle = workbook.createCellStyle();
        Font fontHead = workbook.createFont();
        fontHead.setFontHeightInPoints((short)20);   //字体大小
        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// //居中显示
        cellStyle.setFont(fontHead);

        return cellStyle;

    }


    private static CellStyle setTitleStyle(Workbook workbook, Sheet sheet){

        //字段头样式
        CellStyle cellStyleTitle = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setFontHeightInPoints((short)10);
        font.setBoldweight(Font.BOLDWEIGHT_BOLD);
        cellStyleTitle.setWrapText(true);
        cellStyleTitle.setFont(font);
       /* cellStyleTitle.setBorderRight((short) 1);
        cellStyleTitle.setBorderBottom((short)1);
        cellStyleTitle.setBorderLeft((short)1);
        cellStyleTitle.setBorderTop((short)1);*/
        cellStyleTitle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); // 填充单元格
        cellStyleTitle.setFillForegroundColor(HSSFColor.LIGHT_TURQUOISE.index);
        cellStyleTitle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// //居中显示
        return cellStyleTitle;

    }

    private static void generateTitle(Workbook workbook, Sheet sheet,String[] lableNames){
        int lastRowNum = sheet.getLastRowNum();
        CellStyle cellStyle = setTitleStyle(workbook, sheet);
        //标题行
        Row titleRow = (Row) sheet.createRow(lastRowNum+1);
        for (int i = 0; i < lableNames.length; i++) {
            Cell cell = titleRow.createCell(i);
            cell.setCellValue(lableNames[i]);
            cell.setCellStyle(cellStyle);
            sheet.setColumnWidth(i, lableNames[i].getBytes().length*2*200);
        }
    }


    private static void generateCellMergedRegion(Workbook workbook,Sheet sheet,int firstRow,int lastRow,int firstCol,int lastCol,String head){
        //设置单元格合并
        CellRangeAddress cra=new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
        sheet.addMergedRegion(cra);
        CellStyle cellStyle = setHeadStyle(workbook, sheet);
        //创建第一行进行合并
        Row headRow = sheet.createRow(firstRow);
        for (int i =firstRow+1;i<lastRow;i++){
            Row row = sheet.createRow(i);
        }
        Cell cellHead = headRow.createCell(0);
        cellHead.setCellValue(head);
        cellHead.setCellStyle(cellStyle);
    }



    private static void generateContentRowAsyn(Workbook workbook,Sheet sheet, String[] columnNames, List<Map<String,Object>> list){

     //   CellStyle cellStyle = setColumnRowStyle(workbook);
        if(list != null && list.size() > 0){
            list.stream().forEach(m -> {
                generateContentRow(workbook,sheet, columnNames,m);
            });
        }
    }


    private static void generateContentRow(Workbook workbook,Sheet sheet, String[] columnNames, Map<String,Object> map){
        int lastRowNum = sheet.getLastRowNum();
        Row contentRow = sheet.createRow(++lastRowNum);
        CellStyle cellStyle = setColumnRowStyle(workbook);
        for (int j = 0; j < columnNames.length; j++) {

            Cell cell = contentRow.createCell(j);
            cell.setCellStyle(cellStyle);
           // if(i %2 == 1){
            //    cell.setCellStyle(cellStyle);
         //   }
            if(map != null){

                Object o = map.get(columnNames[j]);
                if(o != null){
                    cell.setCellValue(o.toString());
                }else{
                    cell.setCellValue("");
                }
            }


        }



    }


    private static CellStyle setColumnRowStyle(Workbook workbook){
        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setAlignment(CellStyle.ALIGN_CENTER);// //居中显示
        return cellStyle;

    }

}
